﻿using System.Collections.Immutable;
using DimensionsHelper.LanguageService.Protocol;
using DimensionsHelper.LanguageService.Syntax;

namespace DimensionsHelper.LanguageService.Symbols;

public interface ISymbol
{
    /// <summary>
    ///     符号类型
    /// </summary>
    SymbolKinds Kind { get; }


    /// <summary>
    ///     符号名
    /// </summary>
    string Name { get; }


    /// <summary>
    ///     获取符号的全限定名称
    /// </summary>
    string FullName { get; }


    /// <summary>
    ///     此符号的原始定义，如果此符号不是通过已有符号派生而来的，
    ///     此属性将返回此符号本身
    /// </summary>
    ISymbol OriginalDefinition { get; }


    /// <summary>
    ///     直接包含此符号的符号
    /// </summary>
    ISymbol? ContainingSymbol { get; }


    /// <summary>
    ///     如果是未定义的符号，返回<see langword="true" />
    /// </summary>
    bool IsUndefined { get; }


    /// <summary>
    ///     如果此符号是宏定义，返回<see langword="true" />
    /// </summary>
    bool IsMacro { get; }


    /// <summary>
    ///     如果此符号是本地变量，返回<see langword="true" />
    /// </summary>
    bool IsLocalVariable { get; }


    /// <summary>
    ///     如果此符号是本地常量，返回<see langword="true" />
    /// </summary>
    bool IsConstant { get; }


    /// <summary>
    ///     如果此符号是数组，返回<see langword="true" />
    /// </summary>
    bool IsArray { get; }


    /// <summary>
    ///     如果此符号是数组类型，返回<see langword="true" />
    /// </summary>
    bool IsArrayType { get; }


    /// <summary>
    ///     如果此符号是值类型符号，返回<see langword="true" />
    /// </summary>
    bool IsValueType { get; }


    /// <summary>
    ///     如果此符号是对象类型符号，此属性是<see langword="true" />。
    /// </summary>
    bool IsObjectType { get; }


    /// <summary>
    ///     如果此符号是函数，返回<see langword="true" />
    /// </summary>
    bool IsFunction { get; }


    /// <summary>
    ///     如果此符号是类属性，返回<see langword="true" />
    /// </summary>
    bool IsProperty { get; }


    /// <summary>
    ///     如果此符号是类方法，返回<see langword="true" />
    /// </summary>
    bool IsMethod { get; }


    /// <summary>
    ///     如果此符号是参数，返回<see langword="true" />
    /// </summary>
    bool IsParameter { get; }


    /// <summary>
    ///     如果此符号是Event语句块，返回<see langword="true" />
    /// </summary>
    bool IsEvent { get; }


    /// <summary>
    ///     如果此符号是元数据符号，返回<see langword="true" />
    /// </summary>
    bool IsMetadata { get; }


    /// <summary>
    ///     如果此符号是元数据字段，返回<see langword="true" />
    /// </summary>
    bool IsMetadataField { get; }


    /// <summary>
    ///     如果此符号是元数据简单元素，返回<see langword="true" />
    /// </summary>
    bool IsMetadataElement { get; }


    /// <summary>
    ///     如果此符号可以被派生，返回<see langword="true" />
    /// </summary>
    bool CanBeDerived { get; }


    /// <summary>
    ///     获取所有定义此符号的节点
    /// </summary>
    ImmutableArray<SyntaxLocation> GetLocations();


    /// <summary>
    ///     获取符号在指定文件中的声明节点列表。
    /// </summary>
    /// <param name="fileName">文件名，不区分大小写</param>
    /// <returns>声明区间列表</returns>
    ImmutableArray<SyntaxLocation> GetLocations(string fileName);


    /// <summary>
    ///     获取第一个定义的位置
    /// </summary>
    /// <returns></returns>
    SyntaxLocation GetFirstLocation();


    /// <summary>
    ///     添加一个引用此符号的文本位置
    /// </summary>
    /// <param name="location">引用的文本位置</param>
    void Reference(in SyntaxLocation location);

    
    /// <summary>
    ///     将一个文本位置移除引用
    /// </summary>
    /// <param name="location">指定的文本位置</param>
    void RemoveReference(in SyntaxLocation location);


    /// <summary>
    ///     如果此符号在指定文件的指定位置已经声明，返回<see langword="true" />
    /// </summary>
    /// <param name="fileName">文件名</param>
    /// <param name="position">文本位置</param>
    /// <remarks>
    ///     调用此方法时，此符号已经被引入了当前文件，因此，不需要考虑此符号是否已经声明。
    ///     此方法主要针对 #undef 指令取消宏定义的情况。
    /// </remarks>
    bool IsDeclared(string fileName, int position);


    /// <summary>
    ///     如果此符号在指定文件的指定位置已经声明，返回<see langword="true" />
    /// </summary>
    /// <param name="uri">文件名URI</param>
    /// <param name="position">文本位置</param>
    /// <remarks>
    ///     调用此方法时，此符号已经被引入了当前文件，因此，不需要考虑此符号是否已经声明。
    ///     此方法主要针对 #undef 指令取消宏定义的情况。
    /// </remarks>
    bool IsDeclared(DocumentUri uri, int position);


    /// <summary>
    ///     如果此符号在指定文件的最新位置已声明，返回<see langword="true" />
    /// </summary>
    /// <param name="fileName">文件名</param>
    bool IsDeclared(string fileName);


    /// <summary>
    ///     如果此符号在指定文件的最新位置已声明，返回<see langword="true" />
    /// </summary>
    /// <param name="uri">文件名URI</param>
    bool IsDeclared(DocumentUri uri);


    /// <summary>
    ///     使用给定符号重新声明符号，如果声明失败，返回<see langword="false" />
    /// </summary>
    /// <param name="symbol">重新声明的符号</param>
    bool Redeclare(ISymbol symbol);
}